使用 gulp 实现基于文件内容的指纹

指纹是什么

指纹可以根据文件内容生成文件名。文件内容变化后,文件名也会改变。对于静态内容,或者很少改动的内容,在不同的服务器之间,不同的部署日期之间,使用指纹可以区别文件的两个版本内容是否一样。

为什么需要指纹

如果文件名基于内容而定,而且文件名是唯一的,HTTP 报头会建议在所有可能的地方(CDN,ISP,网络设备,网页浏览器)存储一份该文件的副本。修改文件内容后,指纹会发生变化,因此远程客户端会重新请求文件。这种技术叫做『缓存爆裂』(cache busting)。

为什么要使用基于文件内容的指纹

常见的指纹添加有基于 git 版本的指纹和基于文件内容的指纹。

基于 git 版本的指纹,原理是给每一次提交的文件加上 git 的版本号作为指纹,这样也就是每一份文件共用一个指纹,当有一份文件修改时,提交的 git 版本号就会更改,于是所有的文件指纹都会更新,原有的缓存文件都会失效,不利于缓存的利用。

更好一点的方法是使用基于文件内容的指纹,该指纹根据文件的内容生成,只有文件的内容修改了才会生成新的指纹,文件没做改动则指纹不变,原来的没有修改过的缓存文件仍然能继续使用。

使用 gulp 实现

在 gulp 中使用 gulp-revgulp-rev-collector 可实现基于文件内容的指纹。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// gulpfile.js

var gulp = require('gulp')
var rev = require('gulp-rev')
var revCollector = require('gulp-rev-collector')

gulp.task('hash', function(){
gulp.src('./app.js')
.pipe(rev())
.pipe(gulp.dest('./build/'))
.pipe(rev.manifest())
.pipe(gulp.dest('./'))
})

gulp.task('revcollector', function(){
gulp.src(['./rev-manifest.json', './index.html'])
.pipe(revCollector({
replaceReved: true
}))
.pipe(gulp.dest('./build'))
})

'hash' 任务给文件添加指纹,并且生成 rev-manifest.json 文件:

1
2
3
{
"app.js": "app-e23631ce30.js"
}

revcollector 任务则是根据 rev-manifest.json 文件中的映射关系将目标文件(代码中是 index.html)中的内容做替换。

相关文章

What is Fingerprinting and Why Should I Care?
gulp-rev
gulp-rev-collector